﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using SystemSettings;
using Labthink.PCSoft.UniversalHost4.DataAccess;
using Labthink.PCSoft.UniversalHost4.Instrument.Model;
using Labthink.PCSoft.UniversalHost4.Model;
using Labthink.PCSoft.UniversalHost4.Model.Setting;
using Labthink.PCSoft.UniversalHost4.Model.User;
using Labthink.PCSoft.UniversalHost4.Utility;
using NLog.Fluent;
using FileInfo = System.IO.FileInfo;

namespace Labthink.PCSoft.UniversalHost4
{
    public static class Common
    {
        private static readonly Dictionary<int, List<FullData>> Datas;

        public static TcpCommands.Instrument Instrument { get; set; }
        public static bool IsSign;

        public static string LocalPath { get; set; } = AppDomain.CurrentDomain.BaseDirectory;

        public static string AppPath { get; set; } = AppDomain.CurrentDomain.BaseDirectory;

        /// <summary>
        /// 临时文件夹用于打开报告、导出等操作时，文件的临时存放位置，软件应该定期清理此文件夹
        /// </summary>
        public static string TempPath { get; set; } = Path.Combine(LocalPath, "Temp");

        public static string DbPath { get; set; } = Path.Combine(LocalPath, "Db");

        public static string DefaultParamPath { get; set; } = Path.Combine(LocalPath, "Config");

        public static List<DefaultParam> DefaultParams { get; set; } = new List<DefaultParam>();

        public static DefaultParam CurrentParam { get; set; }

        private static CaliInfo CaliInfo { get; set; }

        public static List<Cali> Calis { get; set; }

        private static SensorCaliInfo SensorCaliInfo { get; set; }

        public static List<SensorCali> SensorCalis { get; set; }

        public static Dictionary<int, ParamProject> AllParamProjects;

        public static DateTime? TestStopTime = null;
        public static bool IsTest { get; set; }

        public static ParamProject CurrentParamProject { get; set; }

        public static List<FullData> SelfQuerys;

        public static int CurrentStandard { get; internal set; }

        public static List<DbLanguage> TestTypes;
        public static Dictionary<string, string> SelfQueryLans;

        public static List<DbLanguage> LanguagesFromDb { get; set; }
        public static List<double> Pls;

        public static UserInfo CurrentUser { get; set; }

        public static UserSettings UserSettings { get; set; }

        public static List<UserPermission> Permissions { get; set; }

        public static UiSetting UiSetting { get; set; }

        public static TestStatus TestStatus { get; set; }

        /// <summary>
        /// 1：待机；2：预热 3：抽真空或充气；4：保压；5：测试；
        /// </summary>
        public static double TestStage { get; set; }

        /// <summary>
        /// 上次密码输入错误时间
        /// </summary>
        public static DateTime LastErrorTime { get; set; } = DateTime.MinValue;

        /// <summary>
        /// 密码输入错误次数
        /// </summary>
        public static int PasswordErrorCount { get; set; }

        public static int MaxCupCount { get; set; } = 3;

        public static BaseInfo BaseInfo { get; set; }

        public static GmpInfo GmpInfo { get; set; }

        public static SafeInfo SafeInfo { get; set; }

        public static CustomInfo CustomInfo { get; set; }

        public static ComInfo ComInfo { get; set; }

        public static TestConfig TestConfig { get; set; }

        public static List<FullData> ParametersInfo { get; set; } = new List<FullData>();

        public static List<ParamForTrace> ParamForTraces { get; set; }

        public static Dictionary<int, string> TestTypeDictionary { get; set; } = new Dictionary<int, string>();

        /// <summary>
        /// 是否是从注销命令到的登陆界面
        /// </summary>
        public static bool IsFromLogout { get; set; }
        //public static List<Result> ltResut = new List<Result>();
        public static string unitPressure = "kPa";
        public static int nDigitPressure;
        public static string unitTempParam = "°C";
        public static int nTestNo; //试验编号，接收自设备
        public static int nTestId; //试验次数，接收自设备
        public static int nDataId; //数据序号，自动累加
        public static int nSampleCount; // 设置的试样件数
        public static string[] arrUnitP = new string[] { "kPa", "mbar", "psi", "mmHg" };
        public static string[] arrResult = new string[] { LanguageManager.GetLanguageValue("Unqualified"), LanguageManager.GetLanguageValue("Qualified"), LanguageManager.GetLanguageValue("Unselected") };
        public static TestMode testMode;

        public static EventHandler<UserAndPermission> LoginSuccessEvent;
        public static event EventHandler<UserAndPermission> LoginSuccess
        {
            add
            {
                if (LoginSuccessEvent == null || !LoginSuccessEvent.GetInvocationList().Contains(value))
                {
                    LoginSuccessEvent += value;
                }
            }
            remove => LoginSuccessEvent -= value;
        }

        static Common()
        {
            Datas = new Dictionary<int, List<FullData>>();
            if (!Directory.Exists(TempPath)) Directory.CreateDirectory(TempPath);
            Pls = new List<double>();
        }

        public static void LoadDefaultParams(string unit)
        {
            DefaultParamPath = Path.Combine(LocalPath, "Config", unit);
            AllParamProjects = new Dictionary<int, ParamProject>();
            if (!Directory.Exists(DefaultParamPath))
            {
                Log.Error().Message("没有找到存放默认参数的文件夹").Write();
                return;
            }

            var conPath = Path.Combine(DefaultParamPath, "dbtemplate_1.lt");
            var sda = new SqliteDataAccess(conPath);
            LanguagesFromDb = sda.GetLanguages();
            GetTestTypes();
            LoadDefaultParam();
        }

        public static void LoadCalis()
        {
            var file = Path.Combine(DefaultParamPath, "Cali.xml");
            CaliInfo = XmlHelper.LoadFromXml<CaliInfo>(file);
            foreach (Cali c in CaliInfo.Calis)
            {
                c.DecayRate ??= "";
            }

            Calis = CaliInfo.Calis;
        }

        public static void SaveCalis()
        {
            var file = Path.Combine(DefaultParamPath, "Cali.xml");
            CaliInfo.Calis = Calis;
            CaliInfo.LastUsed = DateTime.Now;
            XmlHelper.SaveToXml(CaliInfo, file);
        }

        public static void LoadSensorCalis()
        {
            var file = Path.Combine(DefaultParamPath, "Cali_Sensors.xml");
            SensorCaliInfo = XmlHelper.LoadFromXml<SensorCaliInfo>(file);
            SensorCalis = SensorCaliInfo.SensorCalis;
        }

        public static bool SaveSensorCalis()
        {
            var file = Path.Combine(DefaultParamPath, "Cali_Sensors.xml");
            SensorCaliInfo.SensorCalis = SensorCalis;
            return XmlHelper.SaveToXml(SensorCaliInfo, file);
        }

        public static void SendFlowRange()
        {
            //TestConfig = ConfigAndSettings.GetTestConfig();
            //var rangeD = TestConfig.FlowRange.ToDouble();
            //var range = (int)(rangeD * 100); // 流量量程，不受配置的小数位数影响。
            //byte[] bytes = range.ToBytes(2).ToArray();
            //SerialPortHelper.SendCommand(SerialPortCommands.SetFlowRange, SerialPortHelper.X3, bytes);
        }

        private static void GetTestTypes()
        {
            static bool EndWithDigits(DbLanguage t)
            {
                return Regex.IsMatch(t.LanguageId, @"\d+$");
            }

            string f = Path.Combine(DefaultParamPath, "dbtemplate_1.lt");
            if (File.Exists(f))
            {
                TestTypeDictionary.Clear();
                var db = new SqliteDataAccess(f);
                List<DbLanguage> all = db.GetTestTypes();
                List<DbLanguage> testTypes = all.Where(EndWithDigits).ToList();
                TestTypeDictionary = testTypes.ToDictionary(x => Regex.Match(x.LanguageId, @"\d+$").Value.ToInt(), x => x.Text);
            }
        }

        private static void LoadDefaultParam()
        {
            var di = new DirectoryInfo(DefaultParamPath);
            var files = di.GetFiles("DefaultParam*.xml", SearchOption.TopDirectoryOnly);
            foreach (FileInfo file in files)
            {
                DefaultParam dp = XmlHelper.LoadFromXml<DefaultParam>(file.FullName);
                dp.Filename = file.FullName;

                var testType = dp.TestType;

                GetParamInfoFromDb(testType);

                foreach (Param p in dp.Params)
                {
                    FullData fd = ParametersInfo.SingleOrDefault(px => px.DataNo == p.DataNo);
                    if (fd == null)
                    {
                        Log.Debug().Message($"{p.DataNo} is null").Write();
                        continue;
                    }

                    if (p.MaxLength > 0)
                    {
                        // 字符串类型
                        p.Min = -1;
                        p.Max = -1;
                    }
                    else
                    {
                        // 数值类型
                        p.MaxLength = -1;
                    }

                    p.Text = fd.Text;
                    p.Unit = fd.Unit;
                }

                DefaultParams.Add(dp);

                // 加载最后使用的参数方案
                CurrentParam = DefaultParams.OrderByDescending(p => p.LastUsed).First();
            }
        }

        public static List<FullData> MapToFullData(List<Param> ps)
        {
            Log.Debug().Message("MapToFullData");
            List<FullData> fullDatas = ParametersInfo.Clone();
            foreach (FullData fd in fullDatas)
            {
                Param p = ps.SingleOrDefault(px => px.DataNo == fd.DataNo);
                if (p != null)
                {
                    fd.Value = p.Value;
                }
                else
                {
                    Log.Warn().Message($"no {fd.DataNo} in CurrentParam").Write();
                }

                if (fd.DataNo == 10033) //testType
                {
                    fd.Value = 1;
                }

                if (fd.DataNo == 10073) //操作员
                {
                    fd.Value = CurrentUser.UserName;
                }

                if (fd.DataNo == 10074) //testDate
                {
                    fd.Value = DateTime.Now.Date.ToString("d");
                }

                if (fd.DataNo == 10075)
                {
                    fd.Value = DateTime.Now.ToString("HH:mm:ss");
                }
            }

            return fullDatas;
        }

        /// <summary>
        /// 从数据库读取参数信息
        /// </summary>
        /// <param name="testType"></param>
        /// <returns></returns>
        private static void GetParamInfoFromDb(int testType)
        {
            var f = Path.Combine(DefaultParamPath, $"dbtemplate_{testType}.lt");
            if (File.Exists(f))
            {
                var db = new SqliteDataAccess(f);
                ParametersInfo = db.GetParameters();
            }
        }

        public static List<FullData> GetDataTemp(int standard)
        {
            if (Datas.ContainsKey(standard))
                return Datas[standard].Clone();

            var conPath = Path.Combine(DefaultParamPath, "dbtemplate_" + standard + ".lt");
            if (!File.Exists(conPath)) throw new FileNotFoundException("can not found template");
            var da = new SqliteDataAccess(conPath);
            Datas.Add(standard, da.GetData());
            return Datas[standard].Clone();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public static void DeviceInit()
        {
            var initFile = Path.Combine(LocalPath, "init");
            if (File.Exists(initFile)) return;

            using FileStream fs = File.Create(initFile);
            byte[] info = new UTF8Encoding(true).GetBytes("init");
            fs.Write(info, 0, info.Length);

            Process.Start(Application.ResourceAssembly.Location);
            Application.Current.Shutdown();
        }
    }

    [Flags]
    public enum TestStatus
    {
        Idle = 1,
        ParameterSet,
        Start,
        Testing,
        End,
        Abnormal,
        FullySaved,
    }
    public enum TestMode
    {
        /// <summary>
        /// 时间
        /// </summary>
        Time = 1,

        /// <summary>
        /// 位移
        /// </summary>
        Displacement,
    }
    public class UnitT
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }
}
